Finding AIDS impact in r square

Inspired by

R-squared is a statistical measure of how close the data are to the fitted regression line

Topics covered

  • modelling
  • some aspects of purrr
# VHS course "R"Kenntnisse um Wissen aus Daten zu gewinnen 2017
library(gapminder)
library(tidyverse)
library(plotly)

Attaching package: ‘plotly’

The following object is masked from ‘package:ggplot2’:

    last_plot

The following object is masked from ‘package:stats’:

    filter

The following object is masked from ‘package:graphics’:

    layout
tidyverse_packages()
 [1] "broom"     "dplyr"     "forcats"   "ggplot2"   "haven"     "httr"     
 [7] "hms"       "jsonlite"  "lubridate" "magrittr"  "modelr"    "purrr"    
[13] "readr"     "readxl"    "stringr"   "tibble"    "rvest"     "tidyr"    
[19] "xml2"      "tidyverse"

Lets see what is in the data

summary(gapminder)
        country        continent        year         lifeExp           pop           
 Afghanistan:  12   Africa  :624   Min.   :1952   Min.   :23.60   Min.   :6.001e+04  
 Albania    :  12   Americas:300   1st Qu.:1966   1st Qu.:48.20   1st Qu.:2.794e+06  
 Algeria    :  12   Asia    :396   Median :1980   Median :60.71   Median :7.024e+06  
 Angola     :  12   Europe  :360   Mean   :1980   Mean   :59.47   Mean   :2.960e+07  
 Argentina  :  12   Oceania : 24   3rd Qu.:1993   3rd Qu.:70.85   3rd Qu.:1.959e+07  
 Australia  :  12                  Max.   :2007   Max.   :82.60   Max.   :1.319e+09  
 (Other)    :1632                                                                    
   gdpPercap       
 Min.   :   241.2  
 1st Qu.:  1202.1  
 Median :  3531.8  
 Mean   :  7215.3  
 3rd Qu.:  9325.5  
 Max.   :113523.1  
                   
gapminder %>% filter(gdpPercap < 300)
# Print xy plot -----------------------------------------------------------
gapminder <- gapminder %>% mutate(year1950 = year -1950)
ggplot(gapminder, aes(x=year, y=lifeExp)) +geom_line(aes(group = country))

lets transform the data so that we keep all of a country’s data in one row

# Nested data -------------------------------------------------------------
by_country <- gapminder  %>%
  group_by(continent, country) %>%
  nest()
by_country                  # show content of df
str(by_country[1:3,])       # show structure of first 3 rows of grouped and nested df
Classes ‘tbl_df’, ‘tbl’ and 'data.frame':   3 obs. of  3 variables:
 $ continent: Factor w/ 5 levels "Africa","Americas",..: 3 4 1
 $ country  : Factor w/ 142 levels "Afghanistan",..: 1 2 3
 $ data     :List of 3
  ..$ :Classes ‘tbl_df’, ‘tbl’ and 'data.frame':    12 obs. of  5 variables:
  .. ..$ year     : int  1952 1957 1962 1967 1972 1977 1982 1987 1992 1997 ...
  .. ..$ lifeExp  : num  28.8 30.3 32 34 36.1 ...
  .. ..$ pop      : int  8425333 9240934 10267083 11537966 13079460 14880372 12881816 13867957 16317921 22227415 ...
  .. ..$ gdpPercap: num  779 821 853 836 740 ...
  .. ..$ year1950 : num  2 7 12 17 22 27 32 37 42 47 ...
  ..$ :Classes ‘tbl_df’, ‘tbl’ and 'data.frame':    12 obs. of  5 variables:
  .. ..$ year     : int  1952 1957 1962 1967 1972 1977 1982 1987 1992 1997 ...
  .. ..$ lifeExp  : num  55.2 59.3 64.8 66.2 67.7 ...
  .. ..$ pop      : int  1282697 1476505 1728137 1984060 2263554 2509048 2780097 3075321 3326498 3428038 ...
  .. ..$ gdpPercap: num  1601 1942 2313 2760 3313 ...
  .. ..$ year1950 : num  2 7 12 17 22 27 32 37 42 47 ...
  ..$ :Classes ‘tbl_df’, ‘tbl’ and 'data.frame':    12 obs. of  5 variables:
  .. ..$ year     : int  1952 1957 1962 1967 1972 1977 1982 1987 1992 1997 ...
  .. ..$ lifeExp  : num  43.1 45.7 48.3 51.4 54.5 ...
  .. ..$ pop      : int  9279525 10270856 11000948 12760499 14760787 17152804 20033753 23254956 26298373 29072015 ...
  .. ..$ gdpPercap: num  2449 3014 2551 3247 4183 ...
  .. ..$ year1950 : num  2 7 12 17 22 27 32 37 42 47 ...
by_country$data[[1]]        # show data of first row
by_country$data[1]          # show data of first row
[[1]]
by_country$data[[1]][[2]]   # show  contents of second column 
 [1] 28.801 30.332 31.997 34.020 36.088 38.438 39.854 40.822 41.674 41.763 42.129
[12] 43.828
by_country$data[[1]][2]     # show second column
  • [ returns a list
  • [[ returns content of list

a good explanation can be found at: http://r4ds.had.co.nz/vectors.html#lists

structure of dataframe

The column data is a list of data frames. Therefore, we have now a row per country and all data of that country in a dataframe in one column.

In a grouped dataframe each row is an oberservation, in a nested dataframe each row is a group, in this case, a group of a country’s observations.

Lets build a model for each country lifeExp dependend on year

# Fit models --------------------------------------------------------------
country_model <- function(df){
  lm(lifeExp  ~  year1950, data=df)  # use year1950 because the absolute value is not important
}
models <- by_country %>%
  mutate(
    model = map(data, country_model)
  )
models
lm(lifeExp  ~  year1950, data=by_country$data[[1]]) 

Call:
lm(formula = lifeExp ~ year1950, data = by_country$data[[1]])

Coefficients:
(Intercept)     year1950  
    29.3566       0.2753  
models$model[1]
[[1]]

Call:
lm(formula = lifeExp ~ year1950, data = df)

Coefficients:
(Intercept)     year1950  
    29.3566       0.2753  

Use pipe operator to combine all together

# Put it all together -----------------------------------------------------
by_country <- gapminder  %>%
  group_by(continent, country) %>%
  nest() %>%  
  mutate(
    model = map(data, country_model)
  )
by_country

Get the model data in a tidy form using the broom package

models <- models %>%
  mutate(
    glance  = map(model, broom::glance),        # Construct a single row summary "glance" of a model
    rsq     = glance %>% map_dbl("r.squared"),  # note the pipe within mutate(...)
    tidy    = map(model, broom::tidy),          # Tidy the result of a test into a summary data.frame
    augment = map(model, broom::augment)
  )
models
models$glance[1]
[[1]]
models$rsq[1]
[1] 0.9477123
models$tidy[1]
[[1]]
models$augment[1]
[[1]]
NA

lets have a look how well the model fits

models %>% 
  ggplot(aes(rsq, country)) +
  geom_point(aes(colour = continent)) 

# source("gapminderShiny.R")

is the plot clear? how could it be improved?

ggplot orders categorical variables alphabetically

models %>% 
  ggplot(aes(rsq, reorder(country, rsq))) +
  geom_point(aes(colour = continent)) 

find the countries which fit is the worst

  models %>% filter((rsq<0.1 & rsq>0))  %>% unnest(rsq)  %>% top_n(6,rsq) %>% unnest(data) %>% 
    ggplot(aes(year, lifeExp)) +
    geom_line(aes( alpha = 1/3))  +
    facet_wrap(~country)

NA

how much did the countries improve life expectancy over time

# Unnest data -------------------------------------------------------------
unnest(models, data)
unnest(models, glance, .drop = TRUE) 
unnest(models, tidy)
# Plot data frame ---------------------------------------------------------
plotLife <- models %>%
  unnest(tidy) %>%
  select(continent, country, term, estimate, rsq) %>%
  spread(term, estimate) %>%
  ggplot(aes(`(Intercept)`,year1950))+
  geom_point(aes(colour = continent, size = rsq, fill = country)) +
  geom_smooth(se=FALSE) +
  xlab("Life expectancy (1950)") +
  ylab("Yearly improvement") +
  scale_size_area() + guides(fill=FALSE)
ggplotly(plotLife, tooltip = c("year1950", "country"))
`geom_smooth()` using method = 'loess'

where are the exeptions

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Cmd+Option+I.

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Cmd+Shift+K to preview the HTML file).

LS0tCnRpdGxlOiAiR2FwbWluZGVyIGZvciBWSFMgMS8yMDE3IgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICBodG1sX25vdGVib29rOiBkZWZhdWx0Ci0tLQoKIyBGaW5kaW5nIEFJRFMgaW1wYWN0IGluIHIgc3F1YXJlCkluc3BpcmVkIGJ5IAoKLSBURUQgdGFsayBvZiAgKipIYW5zIFJvc2xpbmcqKjogTGV0IG15IGRhdGFzZXQgY2hhbmdlIHlvdXIgbWluZHNldApodHRwczovL3d3dy50ZWQuY29tL3RhbGtzL2hhbnNfcm9zbGluZ19hdF9zdGF0ZSN0LTExNzY0MDcKCi0gKipIYWRsZXkgV2lja2hhbSoqIE1hbmFnaW5nIG1hbnkgbW9kZWxzIHdpdGggUiBodHRwczovL3d3dy55b3V0dWJlLmNvbS93YXRjaD92PXJ6M19GRFZ0OWVnIAoKKipSLXNxdWFyZWQqKiBpcyBhIHN0YXRpc3RpY2FsIG1lYXN1cmUgb2YgaG93IGNsb3NlIHRoZSBkYXRhIGFyZSB0byB0aGUgZml0dGVkIHJlZ3Jlc3Npb24gbGluZQoKIyMgVG9waWNzIGNvdmVyZWQKCi0gbW9kZWxsaW5nCi0gc29tZSBhc3BlY3RzIG9mIHB1cnJyCgoKYGBge3J9CiMgVkhTIGNvdXJzZSAiUiJLZW5udG5pc3NlIHVtIFdpc3NlbiBhdXMgRGF0ZW4genUgZ2V3aW5uZW4gMjAxNwoKbGlicmFyeShnYXBtaW5kZXIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHBsb3RseSkKdGlkeXZlcnNlX3BhY2thZ2VzKCkKYGBgCgoKIExldHMgc2VlIHdoYXQgaXMgaW4gdGhlIGRhdGEKIApgYGB7cn0Kc3VtbWFyeShnYXBtaW5kZXIpCmdhcG1pbmRlciAlPiUgZmlsdGVyKGdkcFBlcmNhcCA8IDMwMCkKIyBQcmludCB4eSBwbG90IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgoKZ2FwbWluZGVyIDwtIGdhcG1pbmRlciAlPiUgbXV0YXRlKHllYXIxOTUwID0geWVhciAtMTk1MCkKZ2dwbG90KGdhcG1pbmRlciwgYWVzKHg9eWVhciwgeT1saWZlRXhwKSkgK2dlb21fbGluZShhZXMoZ3JvdXAgPSBjb3VudHJ5KSkKCmBgYAoKCmxldHMgdHJhbnNmb3JtIHRoZSBkYXRhIHNvIHRoYXQgd2Uga2VlcCBhbGwgb2YgYSBjb3VudHJ5J3MgZGF0YSBpbiBvbmUgcm93CgpgYGB7cn0KCiMgTmVzdGVkIGRhdGEgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKYnlfY291bnRyeSA8LSBnYXBtaW5kZXIgICU+JQogIGdyb3VwX2J5KGNvbnRpbmVudCwgY291bnRyeSkgJT4lCiAgbmVzdCgpCgpieV9jb3VudHJ5ICAgICAgICAgICAgICAgICAgIyBzaG93IGNvbnRlbnQgb2YgZGYKc3RyKGJ5X2NvdW50cnlbMTozLF0pICAgICAgICMgc2hvdyBzdHJ1Y3R1cmUgb2YgZmlyc3QgMyByb3dzIG9mIGdyb3VwZWQgYW5kIG5lc3RlZCBkZgpieV9jb3VudHJ5JGRhdGFbWzFdXSAgICAgICAgIyBzaG93IGRhdGEgb2YgZmlyc3Qgcm93CmJ5X2NvdW50cnkkZGF0YVsxXSAgICAgICAgICAjIHNob3cgZGF0YSBvZiBmaXJzdCByb3cKYnlfY291bnRyeSRkYXRhW1sxXV1bWzJdXSAgICMgc2hvdyAgY29udGVudHMgb2Ygc2Vjb25kIGNvbHVtbiAKYnlfY291bnRyeSRkYXRhW1sxXV1bMl0gICAgICMgc2hvdyBzZWNvbmQgY29sdW1uCmBgYAoKCi0gWyByZXR1cm5zIGEgbGlzdAotIFtbIHJldHVybnMgY29udGVudCBvZiBsaXN0CgphIGdvb2QgZXhwbGFuYXRpb24gY2FuIGJlIGZvdW5kIGF0OiBodHRwOi8vcjRkcy5oYWQuY28ubnovdmVjdG9ycy5odG1sI2xpc3RzIAoKIyMgc3RydWN0dXJlIG9mIGRhdGFmcmFtZQoKVGhlIGNvbHVtbiAqKmRhdGEqKiBpcyBhIGxpc3Qgb2YgZGF0YSBmcmFtZXMuIFRoZXJlZm9yZSwgd2UgaGF2ZSBub3cgYSByb3cgcGVyIGNvdW50cnkgYW5kIGFsbCBkYXRhIG9mIHRoYXQgY291bnRyeSBpbiBhIGRhdGFmcmFtZSBpbiAqKm9uZSoqIGNvbHVtbi4KCkluIGEgZ3JvdXBlZCBkYXRhZnJhbWUgKiplYWNoIHJvdyBpcyBhbiBvYmVyc2VydmF0aW9uKiosIGluIGEgbmVzdGVkIGRhdGFmcmFtZSAqKmVhY2ggcm93IGlzIGEgZ3JvdXAqKiwgaW4gdGhpcyBjYXNlLCBhIGdyb3VwIG9mIGEgY291bnRyeeKAmXMgb2JzZXJ2YXRpb25zLgoKCgoKIyMgTGV0cyBidWlsZCBhIG1vZGVsIGZvciBlYWNoIGNvdW50cnkgbGlmZUV4cCBkZXBlbmRlbmQgb24geWVhcgoKCmBgYHtyfQoKIyBGaXQgbW9kZWxzIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpjb3VudHJ5X21vZGVsIDwtIGZ1bmN0aW9uKGRmKXsKICBsbShsaWZlRXhwICB+ICB5ZWFyMTk1MCwgZGF0YT1kZikgICMgdXNlIHllYXIxOTUwIGJlY2F1c2UgdGhlIGFic29sdXRlIHZhbHVlIGlzIG5vdCBpbXBvcnRhbnQKfQptb2RlbHMgPC0gYnlfY291bnRyeSAlPiUKICBtdXRhdGUoCiAgICBtb2RlbCA9IG1hcChkYXRhLCBjb3VudHJ5X21vZGVsKQogICkKbW9kZWxzCmxtKGxpZmVFeHAgIH4gIHllYXIxOTUwLCBkYXRhPWJ5X2NvdW50cnkkZGF0YVtbMV1dKSAKbW9kZWxzJG1vZGVsWzFdCgpgYGAKCiMjIFVzZSBwaXBlIG9wZXJhdG9yIHRvIGNvbWJpbmUgYWxsIHRvZ2V0aGVyCgpgYGB7cn0KCiMgUHV0IGl0IGFsbCB0b2dldGhlciAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKYnlfY291bnRyeSA8LSBnYXBtaW5kZXIgICU+JQogIGdyb3VwX2J5KGNvbnRpbmVudCwgY291bnRyeSkgJT4lCiAgbmVzdCgpICU+JSAgCiAgbXV0YXRlKAogICAgbW9kZWwgPSBtYXAoZGF0YSwgY291bnRyeV9tb2RlbCkKICApCgpieV9jb3VudHJ5CmBgYAoKCgojIyBHZXQgdGhlIG1vZGVsIGRhdGEgaW4gYSB0aWR5IGZvcm0gdXNpbmcgdGhlICoqYnJvb20qKiBwYWNrYWdlCgpgYGB7cn0KbW9kZWxzIDwtIG1vZGVscyAlPiUKICBtdXRhdGUoCiAgICBnbGFuY2UgID0gbWFwKG1vZGVsLCBicm9vbTo6Z2xhbmNlKSwgICAgICAgICMgQ29uc3RydWN0IGEgc2luZ2xlIHJvdyBzdW1tYXJ5ICJnbGFuY2UiIG9mIGEgbW9kZWwKICAgIHJzcSAgICAgPSBnbGFuY2UgJT4lIG1hcF9kYmwoInIuc3F1YXJlZCIpLCAgIyBub3RlIHRoZSBwaXBlIHdpdGhpbiBtdXRhdGUoLi4uKQogICAgdGlkeSAgICA9IG1hcChtb2RlbCwgYnJvb206OnRpZHkpLCAgICAgICAgICAjIFRpZHkgdGhlIHJlc3VsdCBvZiBhIHRlc3QgaW50byBhIHN1bW1hcnkgZGF0YS5mcmFtZQogICAgYXVnbWVudCA9IG1hcChtb2RlbCwgYnJvb206OmF1Z21lbnQpCiAgKQptb2RlbHMKbW9kZWxzJGdsYW5jZVsxXQptb2RlbHMkcnNxWzFdCm1vZGVscyR0aWR5WzFdCm1vZGVscyRhdWdtZW50WzFdCmBgYAoKIyMgbGV0cyBoYXZlIGEgbG9vayBob3cgd2VsbCB0aGUgbW9kZWwgZml0cwoKCmBgYHtyfQoKbW9kZWxzICU+JSAKICBnZ3Bsb3QoYWVzKHJzcSwgY291bnRyeSkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBjb250aW5lbnQpKSAKIyBzb3VyY2UoImdhcG1pbmRlclNoaW55LlIiKQpgYGAKCmlzIHRoZSBwbG90IGNsZWFyPyBob3cgY291bGQgaXQgYmUgaW1wcm92ZWQ/CgoKCmdncGxvdCBvcmRlcnMgY2F0ZWdvcmljYWwgdmFyaWFibGVzIGFscGhhYmV0aWNhbGx5IAoKYGBge3J9Cgptb2RlbHMgJT4lIAogIGdncGxvdChhZXMocnNxLCByZW9yZGVyKGNvdW50cnksIHJzcSkpKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gY29udGluZW50KSkgCgpgYGAKCiMjIGZpbmQgdGhlIGNvdW50cmllcyB3aGljaCBmaXQgaXMgdGhlIHdvcnN0CgoKYGBge3J9CgogIG1vZGVscyAlPiUgZmlsdGVyKChyc3E8MC4xICYgcnNxPjApKSAgJT4lIHVubmVzdChyc3EpICAlPiUgdG9wX24oNixyc3EpICU+JSB1bm5lc3QoZGF0YSkgJT4lIAogICAgZ2dwbG90KGFlcyh5ZWFyLCBsaWZlRXhwKSkgKwogICAgZ2VvbV9saW5lKGFlcyggYWxwaGEgPSAxLzMpKSAgKwogICAgZmFjZXRfd3JhcCh+Y291bnRyeSkKICAKYGBgCgojIyBob3cgbXVjaCBkaWQgdGhlIGNvdW50cmllcyBpbXByb3ZlIGxpZmUgZXhwZWN0YW5jeSBvdmVyIHRpbWUKCgpgYGB7cn0KCiMgVW5uZXN0IGRhdGEgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKdW5uZXN0KG1vZGVscywgZGF0YSkKdW5uZXN0KG1vZGVscywgZ2xhbmNlLCAuZHJvcCA9IFRSVUUpIAp1bm5lc3QobW9kZWxzLCB0aWR5KQoKIyBQbG90IGRhdGEgZnJhbWUgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgoKcGxvdExpZmUgPC0gbW9kZWxzICU+JQogIHVubmVzdCh0aWR5KSAlPiUKICBzZWxlY3QoY29udGluZW50LCBjb3VudHJ5LCB0ZXJtLCBlc3RpbWF0ZSwgcnNxKSAlPiUKICBzcHJlYWQodGVybSwgZXN0aW1hdGUpICU+JQogIGdncGxvdChhZXMoYChJbnRlcmNlcHQpYCx5ZWFyMTk1MCkpKwogIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IGNvbnRpbmVudCwgc2l6ZSA9IHJzcSwgZmlsbCA9IGNvdW50cnkpKSArCiAgZ2VvbV9zbW9vdGgoc2U9RkFMU0UpICsKICB4bGFiKCJMaWZlIGV4cGVjdGFuY3kgKDE5NTApIikgKwogIHlsYWIoIlllYXJseSBpbXByb3ZlbWVudCIpICsKICBzY2FsZV9zaXplX2FyZWEoKSArIGd1aWRlcyhmaWxsPUZBTFNFKQpnZ3Bsb3RseShwbG90TGlmZSwgdG9vbHRpcCA9IGMoInllYXIxOTUwIiwgImNvdW50cnkiKSkKCgoKYGBgCiMjIHdoZXJlIGFyZSB0aGUgZXhlcHRpb25zCgpgYGB7cn0KCnVubmVzdChtb2RlbHMsIGF1Z21lbnQpICMgdXNpbmcgdGhlIHVubmVzdCB3aXRoIG9uZSBhdWdtZW50IGFyZ3VtZW50IGtlZXBzIHRoZSBncm91cGluZyB2YXJpYWJsZXMgYW5kIGF1Z21lbnQgCgptb2RlbHMgJT4lIHVubmVzdChhdWdtZW50KSAlPiUgCiAgZ2dwbG90KGFlcyh5ZWFyMTk1MCwgLnJlc2lkKSkgKwogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBjb3VudHJ5KSwgYWxwaGEgPSAxLzMpICsKICBnZW9tX3Ntb290aChzZSA9IEZBTFNFKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3VyID0gIndoaXRlIikgKwogIGZhY2V0X3dyYXAofmNvbnRpbmVudCwgc2NhbGVzID0gImZyZWVfeSIpIAoKCmBgYAoKQWRkIGEgbmV3IGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqSW5zZXJ0IENodW5rKiBidXR0b24gb24gdGhlIHRvb2xiYXIgb3IgYnkgcHJlc3NpbmcgKkNtZCtPcHRpb24rSSouCgpXaGVuIHlvdSBzYXZlIHRoZSBub3RlYm9vaywgYW4gSFRNTCBmaWxlIGNvbnRhaW5pbmcgdGhlIGNvZGUgYW5kIG91dHB1dCB3aWxsIGJlIHNhdmVkIGFsb25nc2lkZSBpdCAoY2xpY2sgdGhlICpQcmV2aWV3KiBidXR0b24gb3IgcHJlc3MgKkNtZCtTaGlmdCtLKiB0byBwcmV2aWV3IHRoZSBIVE1MIGZpbGUpLg==